/*
 * DIM-SUM操作系统 - 同步异常处理
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */
#include <dim-sum/errno.h>
#include <dim-sum/linkage.h>
#include <linux/compiler.h>
#include <dim-sum/types.h>
#include <dim-sum/init.h>
#include <dim-sum/stringify.h>
#include <asm/exception.h>
#include <asm/cpu_esr.h>
#include <asm/elx_sync.h>
#include <asm/syscall_entry.h>
#include <asm/memfault.h>
#include <asm/head64.h>
#include <dim-sum/sched.h>
#include <asm-generic/irq_regs.h>

void riscv_timer_interrupt(void);
asmlinkage void handle_mem_fault(struct exception_spot *regs)
{
	BUG_ON(mem_fault(regs, regs->sbadaddr, regs->scause));
}

asmlinkage void handle_unknown_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_insn_misaligned_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_insn_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_insn_illegal_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_load_misaligned_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_load_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_store_misaligned_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_store_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_ecall_u_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_ecall_s_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_ecall_m_fault(struct exception_spot *regs)
{
	BUG();
}

asmlinkage void handle_break_fault(struct exception_spot *regs)
{
	BUG();
}

extern void (*handle_arch_irq)(struct exception_spot *);

asmlinkage void handle_irq_fault(struct exception_spot *regs)
{
	unsigned long scause = regs->scause & ~INTERRUPT_CAUSE_FLAG;
	struct exception_spot *old_regs = set_irq_regs(regs);

	if (scause == INTERRUPT_CAUSE_TIMER) {
		riscv_timer_interrupt();
	} else if (scause == INTERRUPT_CAUSE_SOFTWARE) {
#ifdef CONFIG_SMP
		riscv_software_interrupt();
#else
		BUG();
#endif
	} else if (scause == INTERRUPT_CAUSE_EXTERNAL) {
		if (!handle_arch_irq)
			BUG();
		handle_arch_irq(regs);
	} else {
		BUG();
	}
	set_irq_regs(old_regs);
}

asmlinkage void handle_notify_resume(struct exception_spot *regs,
	unsigned long thread_info_flags)
{
	BUG();
}

asmlinkage void handle_excp_dbg(struct exception_spot *regs)
{
	BUG();
}

void handle_syscall_trace_enter(struct exception_spot *regs)
{
	BUG();
}

void handle_syscall_trace_exit(struct exception_spot *regs)
{
	BUG();
}